#!/usr/bin/python3
#-*-coding:utf-8-*-

###############################################################
## Name       : count_area.py
## Author     : gaojiaming
## Date       : Fri May 12 15:07:00 CST 2023
## Description:
##
##
###############################################################

import sys
import os
import re
import argparse

class Design:#{{{
  def __init__(self, name, area):
    self.name = name
    self.area = area
#}}}

class Libcell:#{{{
  def __init__(self, name, lib, area):
    self.name = name
    self.lib  = lib
    self.area = area
#}}}

class Inst:#{{{
  def __init__(self, name):
    self.name = name
    self.area = 0.0
    self.libcell_num_dict = {}
    self.libcell_dict = {}
    self.design_num_dict = {}
    self.design_dict = {}

  def __str__(self):
    str  = ""
    str += "Libcell:\n"
    for key in self.libcell_num_dict.keys():
      str += "  {0} * {1}\n".format(self.libcell_dict[key].name, self.libcell_num_dict[key])
    str += "Design:\n"
    for key in self.design_num_dict.keys():
      str += "  {0} * {1}\n".format(self.design_dict[key].name, self.design_num_dict[key])
    return str
    
  def add_libcell(self, lib_name, num, libcell):
    self.libcell_num_dict[lib_name] = num
    self.libcell_dict[lib_name] = libcell

  def add_design(self, design_name, num, design):
    self.design_num_dict[design_name] = num
    self.design_dict[design_name] = design
#}}}

def tidy_up_inst(rpt):#{{{
  global design_dict
  global libcell_dict
  design_dict  = {}
  libcell_dict = {}
  tidy_up_list = []
  tidy_up_str  = ""
  with open(rpt, "r") as hd:
    handle = hd.readlines()

    name = ""
    lib  = ""
    area = ""
    lib_status = 0
    rtl_status = 0

    for line in handle:
      re_rtl  = re.match(r"([A-Za-z0-9_]+)\s+([\d\.]+)\s+(\d+)\s+([\d\.]+)", line)
      re_rtl0 = re.match(r"(SNPS_CLOCK_GATE_HIGH_\w+)\s*$", line)
      re_rtl_next = re.search(r"^\s*([\d\.]+)\s+(\d+)\s+([\d\.]+)\s*", line)

      re_lib0 = re.match(r"([A-Z][A-Z0-9_]+)\s*$", line)
      re_lib1 = re.match(r"([A-Z][A-Z0-9_]+)\s+([\w\-]+)\s*$", line)
      re_lib2 = re.match(r"([A-Z][A-Z0-9_]+)\s+([\w\-]+)\s+([\d\.]+)\s+(\d+)\s+([\d\.]+)\s*", line)
      re_lib_next1 = re.search(r"^\s*([\w\-]+)\s*$", line)
      re_lib_next2 = re.search(r"^\s*([\w\-]+)\s+([\d\.]+)\s+(\d+)\s+([\d\.]+)", line)
      re_lib_next3 = re.search(r"^\s*([\d\.]+)\s+(\d+)\s+([\d\.]+)\s*", line)
    
      if lib_status == 1:#only match NOR4V4_90S9T20R
        if re_lib_next1:#match scc14nsfp_90sdb_9tc20_rvt_ssg_v0p72_-40c_ccs
          lib = re_lib_next1.group(1)
          lib_status = 2
          continue
        elif re_lib_next2:#match scc14nsfp_90sdb_9tc20_rvt_ssg_v0p72_-40c_ccs 0.933120 1 0.933120
          lib = re_lib_next2.group(1)
          area= re_lib_next2.group(2)
          num = re_lib_next2.group(3)
          whl = re_lib_next2.group(4)
          libcell = Libcell(name, lib, area)
          libcell_dict[name] = libcell
          tidy_up_list.append("{0} {1} {2} {3} {4}".format(name, lib, area, num, whl))
          lib_status = 0
        else:
          print("P0, sys libcell error at line: ", line)
          os.exit(0)
      elif lib_status == 2:#get NOR4V4_90S9T20R and scc14nsfp_90sdb_9tc20_rvt_ssg_v0p72_-40c_ccs
        if re_lib_next3:
          area= re_lib_next3.group(1)
          num = re_lib_next3.group(2)
          whl = re_lib_next3.group(3)
          libcell = Libcell(name, lib, area)
          libcell_dict[name] = libcell
          tidy_up_list.append("{0} {1} {2} {3} {4}".format(name, lib, area, num, whl))
          #print(name, lib, area)
          lib_status = 0
        else:
          print("P1, sys libcell error at line: ", line)
          os.exit(0)
      elif rtl_status == 1:
        if re_rtl_next:
          area= re_rtl_next.group(1)
          num = re_rtl_next.group(2)
          whl = re_rtl_next.group(3)
          design = Design(name, area)
          design_dict[name] = design
          tidy_up_list.append("{0} {1} {2} {3}".format(name, area, num, whl))
          rtl_status = 0
        else:
          print("P2, sys design error at line: ", line)
          os.exit(0)
      else:
        if re_rtl:
          #print(re_rtl.group(1), re_rtl.group(2), re_rtl.group(3), re_rtl.group(4))
          name = re_rtl.group(1)
          area = re_rtl.group(2)
          #if name == "nova_hand_split_CHANNEL9":
          #  print(area)
          design = Design(name, area)
          design_dict[name] = design
          tidy_up_list.append(line)
          pass
        elif re_rtl0:
          name = re_rtl0.group(1)
          rtl_status = 1
          #print(line)
        elif re_lib0:
          #print(re_lib0.group(1))
          name = re_lib0.group(1)
          lib_status = 1 #only match NOR4V4_90S9T20R
          pass
        elif re_lib1:
          #print(re_lib1.group(1), re_lib1.group(2))
          name = re_lib1.group(1)
          lib  = re_lib1.group(2)
          lib_status = 2 #get NOR4V4_90S9T20R and scc14nsfp_90sdb_9tc20_rvt_ssg_v0p72_-40c_ccs
          #print(name, lib)
          pass
        elif re_lib2:
          #print(re_lib2.group(1), re_lib2.group(2), re_lib2.group(3), re_lib2.group(4), re_lib2.group(5))
          name = re_lib2.group(1)
          lib  = re_lib2.group(2)
          area = re_lib2.group(3)
          libcell = Libcell(name, lib, area)
          libcell_dict[name] = libcell
          tidy_up_list.append(line)
          #print(name)
          pass
        else:
          tidy_up_list.append(line)

  #for lib in libcell_dict.keys():
  #  print(lib)
  #for design in design_dict.keys():
  #  print(design)
  return tidy_up_list
#}}}

def gen_inst_tree(rpt_file_list):#{{{
  global inst_dict 
  
  inst_dict = {}
  top_inst = ""
  inst = Inst(top_inst)
  line_status = 0

  for line in rpt_file_list:
    re_lib = re.match(r"([A-Z][A-Z0-9_]+)\s+([\w\-]+)\s+([\d\.]+)\s+(\d+)\s+([\d\.]+)", line)
    re_rtl = re.match(r"([A-Za-z0-9_]+)\s+([\d\.]+)\s+(\d+)\s+([\d\.]+)", line)
    re_inst= re.match(r"Design: (\w+)", line)
    re_end = re.match(r"Total \d+ references\s+([\d\.]+)", line)

    if line_status == 0:
      if re.match(r"[\-]+", line):
        line_status = 1 #match -------------
        continue
      elif re.match(r"Design : (\w+)", line):
        top_inst = re.match(r"Design : (\w+)", line).group(1)
        inst     = Inst(top_inst)
    elif line_status == 1:
      if re_lib:
        lib = re_lib.group(1)
        num = re_lib.group(4)
        inst.add_libcell(lib, num, libcell_dict[lib])
      elif re_rtl:
        rtl = re_rtl.group(1)
        num = re_rtl.group(3)
        inst.add_design(rtl, num, design_dict[rtl])
      elif re_end:
        inst.area = re_end.group(1)
        line_status = 2 #leave top inst
        inst_dict[top_inst] = inst
        continue
    elif line_status == 2:
      if re.match(r"[\*]+", line):
        line_status = 3
    elif line_status == 3:
      if re_inst:
        inst_name = re_inst.group(1)
        inst = Inst(inst_name)
      elif re_lib:
        lib = re_lib.group(1)
        num = re_lib.group(4)
        inst.add_libcell(lib, num, libcell_dict[lib])
      elif re_rtl:
        rtl = re_rtl.group(1)
        num = re_rtl.group(3)
        inst.add_design(rtl, num, libcell_dict[lib])
      elif re_end:
        inst.area = re_end.group(1)
        line_status = 2
        inst_dict[inst_name] = inst
  return top_inst
#}}}

def ergodic_inst(inst, level=0):
  str = ""
  tab = "  " * level
  nx_level = level+1
   
  for key in sorted(inst.design_dict.keys()):
    rtl = design_dict[key]
    #if key == "nova_hand_split_CHANNEL9":
    #  print("??" + rtl.area)
    str += "{0}{1}  {2}*1  {2} #{{{{{{\n".format(tab, key, rtl.area)
    str += ergodic_inst(inst_dict[key], nx_level)
    str += tab + "#}}}\n"

  for key in sorted(inst.libcell_dict.keys()):
    lib = libcell_dict[key]
    num = inst.libcell_num_dict[key]
    str += "{0}{1}  {2}*{3}  ".format(tab, key, lib.area, num) + "{:.6f}\n".format(float(lib.area)*float(num))

  return str
  
def gen_xls(top_inst):
  str = "INST_NAME  |  Area*Num  |  Whl_Area\n\n"

  inst = inst_dict[top_inst]
  str += "{0}  1  {1} #{{{{{{\n".format(top_inst, inst.area)
  str += ergodic_inst(inst, 1)
  str += "#}}}"
  print(str)

def main():
  rpt = sys.argv[1]
  rpt_file_list = tidy_up_inst(rpt)
  top_inst = gen_inst_tree(rpt_file_list)
  gen_xls(top_inst)

if __name__ == "__main__":
    main()
